package net.borderwars.vm;


import com.sun.org.apache.bcel.internal.classfile.*;
import com.sun.org.apache.bcel.internal.classfile.Method;
import com.sun.org.apache.bcel.internal.classfile.LocalVariable;
import com.sun.org.apache.bcel.internal.classfile.LocalVariableTable;
import com.sun.org.apache.bcel.internal.generic.*;
import com.sun.org.apache.bcel.internal.util.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.TreeMap;

import org.apache.bcel.classfile.*;
import org.apache.bcel.classfile.Code;

/**
 * User: ehubbard
 * Date: Mar 19, 2007
 * Time: 1:37:53 PM
 */
public class MethodStruct {
    private VirtualMachine virtualMachine;

    public MethodStruct(final VirtualMachine virtualMachine, String name) {
        this.virtualMachine = virtualMachine;
        this.name = name;
        virtualMachine.methodByName.put(name, this);

    }

    public String toString() {
        if (bcelMethod != null) {
            return (name + bcelMethod.getSignature());
        } else {
            return (name);
        }
    }

    public void setMethod(Method m) {
        virtualMachine.methodByBcelMethod.put(m, this);
        bcelMethod = m;

        localVariables = new ArrayList<Number>();
        for (int x = 0; x < 100; x++) {
            localVariables.add(x);
        }

        LocalVariableTable lvt = m.getLocalVariableTable();

        for (int x = 0; lvt != null && x < lvt.getTableLength(); x++) {
            LocalVariable lv = lvt.getLocalVariable(x);
            if (lv != null && lv.getStartPC() == 0) {
                if (argCount > 0) {
                    virtualMachine.errln("ArgName " + lv.getName());
                    argNames.addFirst(lv.getName());
                }
                argCount++;
            }
        }

    }

    private TreeMap<Integer, Instruction> indexInstructions(byte data[], String className, String methodName) {
        String key = className + ":" + methodName;
        TreeMap<Integer, Instruction> rtn = null;
        if (VirtualMachine.cachedInstructions.containsKey(key) && virtualMachine.cacheInstructions) {
            rtn = (TreeMap<Integer, Instruction>) VirtualMachine.cachedInstructions.get(key);
            return (rtn);
        }

        ByteSequence bs = new ByteSequence(data);
        rtn = new TreeMap<Integer, Instruction>();

        try {
            while (true) {
                int idx = bs.getIndex();
                Instruction i = Instruction.readInstruction(bs);
                rtn.put(VirtualMachine.getInteger(idx), i);
            }
        }
        catch (IOException e) {
            // done
        }
        if (virtualMachine.cacheInstructions)
            VirtualMachine.cachedInstructions.put(key, rtn);
        //  System.out.println(key + " " + rtn);
        return (rtn);
    }

    TreeMap<Integer, Instruction> instructions = null;
    LinkedList<String> argNames = new LinkedList<String>();
    String name = null;
    int argCount = 0;
    Code bcelMethodCode = null;
    Method bcelMethod = null;
    private byte instructionBytes[] = null;
    ArrayList<Number> localVariables = null;

    public TreeMap<Integer, Instruction> getInstructions() {
        return (instructions);
    }

    public void setMethodBytes(byte[] code, String className, String methodName) {
        instructions = indexInstructions(code, className, methodName);
    }

}
